iT邦幫忙

2023 iThome 鐵人賽

DAY 24
0

今天開始來處理上傳檔案到GoogleDrive的部分~

首先要先能在LineBot上拿到使用者傳送的檔案,我們在Callback加上一個case,透過*linebot.FileMessage來判斷傳送的類型是檔案,接著比較不一樣的是沒辦法直接透過message.XXX拿到檔案內容,而是要從message拿到ID並透過GetMessageContent()把傳送的檔案內容取出來。

// internal\router\api\v1\callback.go
case *linebot.FileMessage:
	lineID := event.Source.UserID
	content, err := app.LineBotClient.GetMessageContent(message.ID).Do()
	if err != nil {
		log.Println(err)
		return
	}
	
	app.DriveService.UploadFile(ctx, lineID, message.FileName, content.Content)
	if err != nil {
		log.Println(err)
		return
	}
	if _, err = app.LineBotClient.ReplyMessage(event.ReplyToken, linebot.NewTextMessage("成功上傳: "+message.FileName)).Do(); err != nil {
		log.Println(err)
	}

接著我們來實現上面DriveService的UploadFile,輸入中的message.FileName是從Line拿到的檔案名稱,同時也是我們檔案上傳到Drive的名稱,content.Content則是一個熟悉的io.ReadCloser,我們可以操控他來進行檔案的操作。

這邊先大概講一下這個Service做了什麼,我們一樣先去拿Dynamodb的token然後New一個可以操作的GoogleDrive出來,接著把剛剛收到的content丟到domain裡去儲存到本地端,接著上傳檔案到指定的資料夾內。

// internal\app\service\drive\drive_service.go
func (dr *GoogleDriveService) UploadFile(ctx context.Context, lineID string, fileName string, content io.ReadCloser) error {
	dToken, err := dr.driveServiceDynamodb.GetGoogleOAuthToken(lineID)

	if err != nil {
		log.Println(err)
		return err
	}

	tok := oauth2.Token{
		AccessToken:  dToken.AccessToken,
		TokenType:    dToken.TokenType,
		RefreshToken: dToken.RefreshToken,
		Expiry:       dToken.Expiry,
	}

	d, err := dr.driveServiceGoogleOA.NewGoogleDrive(ctx, &tok)
	if err != nil {
		log.Println(err)
		return err
	}

	file, err := domainDrive.SaveContent(content)
	if err != nil {
		log.Println(err)
		return err
	}
	

	log.Println("START Upload File To Drive")
	// 假設預設的儲存路徑
	folderID := "1kpLZfvk9XmSr4xtDvczAqYHIF8P3r8bk"
	err = d.UploadFile(folderID, fileName, file)
	if err != nil {
		log.Println("err:", err)
		return err
	}
	return nil

}

那我們先來看domain的部分,首先domain下建立drive\drive.go,還有在最外層目錄建立tmp資料夾。我們會透過os.CreateTemp./tmp下建立暫存檔,透過io.Copy把content複製進去,寫完檔案後要記得file.Seek(0, 0)把檔案指到開頭,別人在使用我們回傳的*os.File時才能順利從頭讀到檔案,最後就可以把content關了。

package drive

import (
	"io"
	"log"
	"os"
)

// Save content to ./tmp
func SaveContent(content io.ReadCloser) (*os.File, error) {
	defer content.Close()
	file, err := os.CreateTemp("./tmp", "")
	if err != nil {
		return nil, err
	}
	_, err = io.Copy(file, content)
	if err != nil {
		return nil, err
	}
	_, err = file.Seek(0, 0)
	if err != nil {
		return nil, err
	}
	log.Printf("Saved %s", file.Name())
	return file, nil
}

這邊可以注意到我只有defer content.Close(),但是並沒有寫defer file.Close(),因為我們希望直接透過這個*os.File讓adapter直接將檔案上傳到google drive上。

到這邊我們先註解掉drive_service.golog.Println("START Upload File To Drive")下面的那些code,然後建立一個測試的txt。

https://ithelp.ithome.com.tw/upload/images/20231009/20115990xvI5DwS5qU.png

測試.txt丟到我們的Linebot上
https://ithelp.ithome.com.tw/upload/images/20231009/20115990gQooczZKdb.png
https://ithelp.ithome.com.tw/upload/images/20231009/20115990u6kUqie73w.png
https://ithelp.ithome.com.tw/upload/images/20231009/20115990k5oPzpKmvg.png
可以看到tmp下面就成功建立了暫存檔,同時裡面的內容也有被正確的寫入,那我們今天就先寫到這,明天再繼續寫adapter的部分,明天見囉~


上一篇
Day23 Drive Service - 撈出”我的雲端硬碟”&”與我共用”下的資料夾
下一篇
D25 Drive Service - 上傳檔案02
系列文
Golang LineBot X GoogleDrive:LINE有各種限制!? 那就丟上Drive吧!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言